#include "XBaseSocket.h"

#include "XBaseError.h"
#include "XUtility.h"

XIMPL_LOGGER(XBaseSocket, logger);

XBaseSocket::XBaseSocket()
{
	XLOG4CPLUS_GUARD( logger, __FUNCTION__ );
	
	_socket_fd = -1;
	mErrno = 0;
}
XBaseSocket::~XBaseSocket()
{
	XLOG4CPLUS_GUARD( logger, __FUNCTION__ );
}

void XBaseSocket::init(const  std::string & ip, int port, uint32_t recvTimeoutMs, uint32_t sendTimeoutMs)
{
	XLOG4CPLUS_GUARD( logger, __FUNCTION__ );

	XLOG4CPLUS_DEBUG( logger, "INPUT: ip=" << ip << ",port=" << port << ",recvTimeoutMs=" << recvTimeoutMs << ",sendTimeoutMs=" << sendTimeoutMs );
	
	_ip = ip;
	_port = port;
	mRecvTimeoutMs = recvTimeoutMs;
	mSendTimeoutMs = sendTimeoutMs;
}

bool XBaseSocket::is_connected()
{
	XLOG4CPLUS_GUARD( logger, __FUNCTION__ );

	XLOG4CPLUS_DEBUG( logger, " _socket_fd=" << _socket_fd << ",_ip=" << _ip << ",_port=" << _port );
	
	return (_socket_fd != -1);
}

bool XBaseSocket::reconnect()
{
	XLOG4CPLUS_GUARD( logger, __FUNCTION__ );

	close();

	_socket_fd = xopen(_ip.c_str(), _port, SOCK_CLIENT_TYPE);	
	if (_socket_fd < 0) {
		XLOG4CPLUS_DEBUG( logger, "xopen(" << _ip << ", " << _port << ") fail: " << strerror( errno ) );

		mErrno = XERROR_SERVER_CONNECT;
		
		mErrstr = ": ";
		mErrstr += strerror( errno );
		mErrstr += " (";
		mErrstr += _ip;
		mErrstr += ":";
		mErrstr += XUtility::int32_2_string( _port );
		mErrstr += ")";
		
	}
	else {
		XLOG4CPLUS_DEBUG(logger, "xopen(" << _ip << ", " << _port << ") succ: _socket_fd=" << _socket_fd );
	}

	return (_socket_fd != -1);
}

void XBaseSocket::close()
{
	XLOG4CPLUS_GUARD( logger, __FUNCTION__ );

	XLOG4CPLUS_DEBUG(logger, " _ip=" << _ip << ",_port=" << _port << ",_socket_fd=" << _socket_fd );

	if ( _socket_fd >= 0 ) {
		xclose(_socket_fd);
		_socket_fd = -1;
	}
}

void XBaseSocket::set_recv_timeout(uint32_t timeoutMs)
{
	mRecvTimeoutMs = timeoutMs;
}
void XBaseSocket::set_send_timeout(uint32_t timeoutMs)
{
	mSendTimeoutMs = timeoutMs;
}
int XBaseSocket::send_request(const char * buffer, size_t buffer_size)
{
	XLOG4CPLUS_GUARD( logger, __FUNCTION__ );

	int send_ret = xsend_data(_socket_fd, buffer, buffer_size, mSendTimeoutMs);
	if (send_ret != (int)buffer_size) {
		XLOG4CPLUS_DEBUG(logger, "xsend_data(" << _socket_fd << ", , " << buffer_size << ", " << mSendTimeoutMs <<  ") fail: " << strerror ( errno )
			<< " (_ip=" << _ip << ",_port=" << _port << ")");

		mErrno = XERROR_SERVER_SEND;

		mErrstr = ": ";
		mErrstr += strerror( errno );
		mErrstr += " (";
		mErrstr += _ip;
		mErrstr += ":";
		mErrstr += XUtility::int32_2_string( _port );
		mErrstr += ")";

	}
	else {
		XLOG4CPLUS_DEBUG(logger, "xsend_data(" << _socket_fd << ", , " << buffer_size << ", " << mSendTimeoutMs <<  ") succ: "
			<< " (_ip=" << _ip << ",port=" << _port << ")");
	}
	
	return send_ret;
}

int XBaseSocket::recv_response(char * buffer, size_t buffer_size)
{
	XLOG4CPLUS_GUARD( logger, __FUNCTION__ );

	// head
	int head_size = _protocol.get_head_length();
	int recv_size = xrecv_data(_socket_fd, buffer, head_size, mRecvTimeoutMs);
	if (recv_size != (int)_protocol.get_head_length()) {
		XLOG4CPLUS_DEBUG(logger, "xrecv_head(" << _socket_fd << ", , " << head_size << ", " << mRecvTimeoutMs <<  ") fail: " << strerror( errno )
			<< " (_ip=" << _ip << ",port=" << _port << ")");

		mErrno = XERROR_SERVER_RECV;

		mErrstr = ": ";
		mErrstr += strerror( errno );
		mErrstr += " (";
		mErrstr += _ip;
		mErrstr += ":";
		mErrstr += XUtility::int32_2_string( _port );
		mErrstr += ")";

		return -1;
	}
	XLOG4CPLUS_DEBUG(logger, "xrecv_head(" << _socket_fd << ", , " << head_size << ", " << mRecvTimeoutMs <<  ") succ: "
		<< " (_ip=" << _ip << ",_port=" << _port << ")");

	// body
	size_t body_size = _protocol.get_body_length(buffer, recv_size);
	if (body_size > (buffer_size-head_size)) {
		XLOG4CPLUS_DEBUG(logger, "body_size " << body_size << "(" << (buffer_size-head_size) << ") too large");

		mErrno = XERROR_SERVER_RECV;
		
		mErrstr = ": Invalid body_size ";
		mErrstr += XUtility::int32_2_string( body_size );
		mErrstr += " (";
		mErrstr += _ip;
		mErrstr += ":";
		mErrstr += XUtility::int32_2_string( _port );
		mErrstr += ")";
			
		return -1;
	}
	
	recv_size = xrecv_data(_socket_fd, buffer+head_size, body_size, mRecvTimeoutMs);
	if (recv_size != (int)body_size) {
		XLOG4CPLUS_DEBUG(logger, "xrecv_body(" << _socket_fd << ", , " << head_size << ", " << mRecvTimeoutMs <<  ") fail: " << strerror( errno )
			<< " (_ip=" << _ip << ",port=" << _port << ")");

		mErrno = XERROR_SERVER_RECV;
		
		mErrstr = ": ";
		mErrstr += strerror( errno );
		mErrstr += " (";
		mErrstr += _ip;
		mErrstr += ":";
		mErrstr += XUtility::int32_2_string( _port );
		mErrstr += ")";

		return -1;
	}
	XLOG4CPLUS_DEBUG(logger, "xrecv_body(" << _socket_fd << ", , " << head_size << ", " << mRecvTimeoutMs <<  ") succ: "
		<< " (_ip=" << _ip << ",_port=" << _port << ")");

	return (head_size + body_size);
}

